/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package muhnes.sizoo.filtros;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.context.ManagedSessionContext;

public class TransaccionesHibernateFilter implements Filter {
 
    protected SessionFactory creadorSesiones;
    protected String HIBERNATE_SESSION_KEY;
    protected String END_OF_CONVERSATION_FLAG;
    protected String CURRENT_VIEW;
    
    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {
        
        org.hibernate.classic.Session currentSession;
 
        // Try to get a Hibernate Session from the HttpSession
        HttpSession httpSession = ((HttpServletRequest) request).getSession();
        Session disconnectedSession = (Session) httpSession.getAttribute(HIBERNATE_SESSION_KEY);
        String vista = (String) httpSession.getAttribute( CURRENT_VIEW );
        String vistaActual = ((HttpServletRequest) request).getRequestURI();
        
        if( vistaActual != null && !vistaActual.endsWith(".xhtml")) {
            return;
        }
        
        try {
        
            // End or continue the long-running conversation?
            if (disconnectedSession != null && vista != null && vistaActual != null
                && !vistaActual.equals( vista )) {
 
                //Limpiando sesion
                disconnectedSession.getTransaction().commit();
 
                //Cerrando la sesion
                disconnectedSession.close();
                disconnectedSession = null;
 
                //Limpiando la sesion
                if( ((HttpServletRequest) request).isRequestedSessionIdValid() ) {
                    httpSession.setAttribute(HIBERNATE_SESSION_KEY, null);
                    httpSession.setAttribute(CURRENT_VIEW, null);
                }
 
            }
 
            // Start a new conversation or in the middle?
            if (disconnectedSession == null) {
                //Nueva conversacion
                currentSession = creadorSesiones.openSession();
                currentSession.setFlushMode(FlushMode.MANUAL);
                //Iniciando transaccion en la base de datos
                currentSession.beginTransaction();
                //Guardando la conversación actual
                if( ((HttpServletRequest) request).isRequestedSessionIdValid() ) {
                    httpSession.setAttribute(HIBERNATE_SESSION_KEY, currentSession);
                    httpSession.setAttribute(CURRENT_VIEW, vistaActual);
                }
            } else {
                //Continuando con conversacion activa
                currentSession = (org.hibernate.classic.Session) disconnectedSession;
            }
 
            //Enlazando la sesion actual
            ManagedSessionContext.bind(currentSession);
            
 
            //Procesando los eventos
            chain.doFilter(request, response);
 
            //Desenlazando la sesion despues del procesamiento de eventos
            currentSession = ManagedSessionContext.unbind(creadorSesiones);
 
            
 
                //Guardando los cambios en la base de datos
                //currentSession.getTransaction().commit();
 
        } catch (StaleObjectStateException staleEx) {
            // Rollback, close everything, possibly compensate for any permanent changes
            // during the conversation, and finally restart business conversation. Maybe
            // give the user of the application a chance to merge some of his work with
            // fresh data... what you do here depends on your applications design.
            throw staleEx;
        } catch (Throwable ex) {
            // Rollback only
            try {
                if (creadorSesiones.getCurrentSession().getTransaction().isActive()) {
                    creadorSesiones.getCurrentSession().getTransaction().rollback();
                }
            } catch (Throwable rbEx) {
                
            } finally {

                //Desenlazando sesion despues de excepcion
                currentSession = ManagedSessionContext.unbind(creadorSesiones);
 
                //Cerando sesion después de excepcion
                currentSession.close();
 
                //Limpiando la sesion
                if( ((HttpServletRequest) request).isRequestedSessionIdValid() ) {
                    httpSession.setAttribute(HIBERNATE_SESSION_KEY, null);
                    httpSession.setAttribute(CURRENT_VIEW, null);
                }
 
            }
 
            // Let others handle it... maybe another interceptor for exceptions?
            throw new ServletException(ex);
        }
    }
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}
 
    @Override
    public void destroy() {}
 
}
